<!doctype html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">

    <title>angular js自定义指令 directive 如何使用？为什么要使用封装的自定义指令？</title>

    <link rel="stylesheet" href="../css/reveal/reveal.css">

    <!-- PPT主题，可以在/css/reveal/theme/中选择其他主题，目前暂时只能使用该模板 -->
    <link rel="stylesheet" href="../css/reveal/theme/ptt.css">

    <!-- syntax highlighting 代码高亮主题 -->
    <link rel="stylesheet" href="../lib/reveal/css/zenburn.css">

    <!-- 打印和PDF输出样式 -->
    <script>
        var link = document.createElement('link');
        link.rel = 'stylesheet';
        link.type = 'text/css';
        link.href = window.location.search.match(/print-pdf/gi) ? '../css/reveal/print/pdf.css' : '../css/reveal/print/paper.css';
        document.getElementsByTagName('head')[0].appendChild(link);
    </script>
</head>
<body>
<img src="../img/demo/logo.png" alt="" usemap="#pttmap" class="base-logo">
<map name="pttmap">
    <area shape="rect" coords="0,0,276,58" href="http://www.jnshu.com" alt="" target="_blank"/>
</map>
<div class="reveal">
    <div class="slides">
        <section>
            <h2>【JS-8】</h2>
            <h3>angular js自定义指令 directive 如何使用？</h3>
            <p>分享人：郭健锋</p>
        </section>

        <section>
            <p>目录</p>
            <p>1.背景介绍</p>
            <p>2.知识剖析</p>
            <p>3.常见问题</p>
            <p>4.解决方案</p>
            <p>5.编码实战</p>
            <p>6.扩展思考</p>
            <p>7.参考文献</p>
            <p>8.更多讨论</p>
        </section>
        <section>
            <h3>一.背景介绍</h3>
        </section>
        <section>
            <p>指令定义</p>
            <p style="text-align:left">
                对于指令，可以把它简单的理解成在特定DOM元素上运行的函数，指令可以扩展这个元素
                的功能。</p>
            <p style="text-align:left">例如， ng-click 可以让一个元素能够监听 click 事件，并在接收到事件的时候执行AngularJS表
                达式。正是指令使得AngularJS这个框架变得强大，并且正如所见，我们可以自己创造新的指令。
                AngularJS应用的模块中有很多方法可以使用，其中 directive( )这个模块是用来定义指令的。</p>
        </section>
        <section>
            <h3>二.知识剖析</h3>
        </section>
        <section>
            <p>directive( )模块解析</p>
        </section>
        <section>
            <P>directive( )方法可以接受两个参数：</P>
            <p style="text-align:left">1. name （字符串）</p>
            <p style="text-align:left">指令的名字，用来在视图中引用特定的指令。</p>
            <p style="text-align:left">2. factory_function （函数）</p>
            <p style="text-align:left">这个函数返回一个对象，其中定义了指令的全部行为。 $compile 服务利用这个方法返回的对
                象，在DOM调用指令时来构造指令的行为。</p>
            <pre>
                <code>
angular.application('myApp', [])
    .directive('myDirective', function() {
    // 一个指令定义对象
    return {
    // 通过设置项来定义指令，在这里进行覆写
    };
});        
                </code>
            </pre>
        </section>
        <section>
            <p style="text-align:left">当AngularJS启动应用时，它会把第一个参数当作一个字符串，并以此字符串为名来注册第
                二个参数返回的对象。AngularJS编译器会解析主HTML的DOM中的元素、属性、注释和CSS类名
                中使用了这个名字的地方，并在这些地方引用对应的指令。当它找到某个已知的指令时，就会在
                页面中插入指令所对应的DOM元素。</p>
            <pre>
                <code>
             <div my-directive></div>
                </code>
            </pre>
            <p style="text-align:left">tips:为了避免与未来的HTML标准冲突，给自定义的指令加入前缀来代表自定义的
                命名空间。AngularJS本身已经使用了 ng- 前缀，所以可以选择除此以外的名字。
                在例子中我们使用 my- 前缀（比如 my-derictive ）。</p>
        </section>
        <section>
            <p style="text-align:left">当模板在上面代码中返回时，你可以把以下的属性列表应用于指令定义返回的对象</p>
        </section>
        <section>
            <p>restrict（字符串）</p>
            <p style="text-align:left">restrict 是一个可选的参数。它告诉AngularJS这个指令在DOM中可以何种形式被声明。默
                认AngularJS认为 restrict 的值是 A ，即以属性的形式来进行声明。</p>
            <p style="text-align:left">可选值如下：</p>
            <pre>
                <code>
            E（元素）
            <my-directive></my-directive>
            A（属性，默认值）
            <div my-directive="expression"></div>
            C（类名）
            <div class="my-directive:expression;"></div>
            M（注释）
            <--directive:my-directive expression-->
            这些选项可以单独使用，也可以混合在一起使用：
            angular.module('myDirective', function(){
                return {
                restrict: 'EA' // 输入元素或属性
                };
            });
                </code>
            </pre>
        </section>
        <section>
            <p> template （字符串或函数）</p>
            <p style="text-align:left">template 参数是可选的，必须被设置为以下两种形式之一：</p>
            <p style="text-align:left"> 一段HTML文本；</p>
            <p style="text-align:left"> 一个可以接受两个参数的函数，参数为 tElement 和 tAttrs ，并返回一个代表模板的字符
                串。 tElement 和 tAttrs 中的 t 代表 template ，是相对于 instance 的。在讨论链接和编译
                设置时会详细介绍，模板元素或属性与实例元素或属性之间的区别。</p>
            <p style="text-align:left">AngularJS会同处理HTML一样处理模板字符串。模板中可以通过大括号标记来访问作用域，
                例如 {{ expression }} 。</p>
        </section>
        <section>
            <p>templateUrl （字符串或函数）</p>
            <p style="text-align:left">templateUrl 是可选的参数，可以是以下类型：</p>
            <p style="text-align:left"> 一个代表外部HTML文件路径的字符串；</p>
            <p style="text-align:left"> 一个可以接受两个参数的函数，参数为 tElement 和 tAttrs ，并返回一个外部HTML文件
                路径的字符串。</p>
            <p style="text-align:left">无论哪种方式，模板的URL都将通过AngularJS内置的安全层，特别是 $getTrusted
                ResourceUrl ，这样可以保护模板不会被不信任的源加载。</p>
        </section>
        <section>
            <p>transclude</p>
            <p style="text-align:left">transclude 是一个可选的参数。如果设置了，其值必须为 true ，它的默认值是 false 。</p>
            <p style="text-align:left">嵌入有时被认为是一个高级主题，但某些情况下它与我们刚刚学习过的作用域之间会有非常
                好的配合。使用嵌入也会很好地扩充我们的工具集，特别是在创建可以在团队、项目、AngularJS
                社区之间共享的HTML代码片段时。</p>
            <p style="text-align:left">嵌入通常用来创建可复用的组件，典型的例子是模态对话框或导航栏。</p>

        </section>

        <section>
            <p style="text-align:left">我们可以将整个模板，包括其中的指令通过嵌入全部传入一个指令中。这样做可以将任意内
                容和作用域传递给指令。 transclude 参数就是用来实现这个目的的，指令的内部可以访问外部
                指令的作用域，并且模板也可以访问外部的作用域对象。</p>
            <p style="text-align:left">为了将作用域传递进去， scope 参数的值必须通过 {} 或 true 设置成隔离作用域。如果没有设
                置 scope 参数，那么指令内部的作用域将被设置为传入模板的作用域。</p>
            <p style="text-align:left">只有当你希望创建一个可以包含任意内容的指令时，才使用 transclude: true 。</p>

        </section>
        <section>
            <h3>三.常见问题</h3>
        </section>
        <section>
            <p>如何创建操作DOM的指令？</p>
        </section>
        <section>
            <h3>四.解决方案</h3>
        </section>
        <section>
        <p style="text-align:left">要修改DOM的指令通常使用链接选项来注册DOM侦听器以及更新DOM。它是在模板被克隆后执行的，是指令逻辑将被执行的地方。</p>
        <p style="text-align:left">链接的功能与下面的签名，功能链接(scope，element，attrs，controller，transcludeFn){…},:</p>
        <p style="text-align:left">scope是一个Angular scope 对象。</p>
        <p style="text-align:left">element是这个指令匹配的jqlite包装元素。</p>
        <p style="text-align:left">attrs是一个哈希对象，其具有键值对标准化属性名及其相应的属性值。</p>
        <p style="text-align:left">controller是指令的必需控制器实例(s)或它自己的控制器(如果有的话)。确切的值取决于指令的要求属性。</p>
        <p style="text-align:left">transcludeFn是一个连接函数预绑定到正确的连接函数。</p>
        </section>
        <section>
        <p style="text-align:left">在我们的link函数中，我们希望每秒更新显示的时间，或者每当用户更改指令绑定到的时间格式字符串时。
        我们将使用$ interval服务定期调用处理程序。这比使用$ timeout更容易，但也可以更好地使用端到端测试，
        我们希望确保在完成测试之前完成所有$ timeouts。如果指令被删除，我们还希望删除$ interval，这样我们就不会引入内存泄漏。</p>
        </section>
        <section>
            <h3>五.编码实战</h3>
        </section>
        <section>
            <pre>
                <code>
angular.module('docsTimeDirective', [])
.controller('Controller', ['$scope', function($scope) {
  $scope.format = 'M/d/yy h:mm:ss a';
}])
.directive('myCurrentTime', ['$interval', 'dateFilter', function($interval, dateFilter) {

  function link(scope, element, attrs) {
    var format,
        timeoutId;

    function updateTime() {
      element.text(dateFilter(new Date(), format));
    }

    scope.$watch(attrs.myCurrentTime, function(value) {
      format = value;
      updateTime();
    });

    element.on('$destroy', function() {
      $interval.cancel(timeoutId);
    });

    // start the UI update process; save the timeoutId for canceling
    timeoutId = $interval(function() {
      updateTime(); // update DOM
    }, 1000);
  }

  return {
    link: link
  };
}]);
                </code>
            </pre>
        </section>
        <section>
            <h3>六.拓展思考</h3>
            <p>创建一个包含其他元素的指令</p>
            <pre>
                <code>
            angular.module('docsTransclusionDirective', [])
            .controller('Controller', ['$scope', function($scope) {
            $scope.name = 'Tobias';
            }])
            .directive('myDialog', function() {
            return {
            restrict: 'E',
            transclude: true,
            scope: {},
            templateUrl: 'my-dialog.html'
            };
            });
                </code>
            </pre>
        </section>
        <section>
            <h3>七.参考文献</h3>
        </section>
        <section>
            <p><a href="https://code.angularjs.org/1.6.6/docs/guide/directive">angular自定义指令官方指南</a></p>
            <p><a href="http://www.cnblogs.com/liulangmao/tag/angular/default.html?page=2">流浪猫の窝</a></p>
        </section>
        <section>
            <h3>八.更多讨论</h3>
            <p>为什么不推荐Angular和JQuery混合使用？</p>
        </section>
        <section>
            <h4>鸣谢</h4>
            <p>感谢大家观看</p>
            <p>BY : 郭健锋</p>
        </section>

    </div>
</div>

<script src="../lib/reveal/js/head.min.js"></script>
<script src="../lib/reveal/reveal.js"></script>

<script>

    // 以下为常见配置属性的默认值
    // {
    // 	controls: true, // 是否在右下角展示控制条
    // 	progress: true, // 是否显示演示的进度条
    // 	slideNumber: false, // 是否显示当前幻灯片的页数编号，也可以使用代码slideNumber: 'c / t' ，表示当前页/总页数。
    // 	history: false, // 是否将每个幻灯片改变加入到浏览器的历史记录中去
    // 	keyboard: true, // 是否启用键盘快捷键来导航
    // 	overview: true, // 是否启用幻灯片的概览模式，可使用"Esc"或"o"键来切换概览模式
    // 	center: true, // 是否将幻灯片垂直居中
    // 	touch: true, // 是否在触屏设备上启用触摸滑动切换
    // 	loop: false, // 是否循环演示
    // 	rtl: false, // 是否将演示的方向变成RTL，即从右往左
    // 	fragments: true, // 全局开启和关闭碎片。
    // 	autoSlide: 0, // 两个幻灯片之间自动切换的时间间隔（毫秒），当设置成 0 的时候则禁止自动切换，该值可以被幻灯片上的 ` data-autoslide` 属性覆盖
    // 	transition: 'default', // 切换过渡效果，有none/fade/slide/convex/concave/zoom
    // 	transitionSpeed: 'default', // 过渡速度，default/fast/slow
    // 	mouseWheel: true, //是否启用通过鼠标滚轮来切换幻灯片
    // }

    // 初始化幻灯片
    Reveal.initialize({
        history: true,
        dependencies: [
            {src: '../plugin/markdown/marked.js'},
            {src: '../plugin/markdown/markdown.js'},
            {src: '../plugin/notes/notes.js', async: true},
            {
                src: '../plugin/highlight/highlight.js',
                async: true,
                callback: function () {
                    hljs.initHighlightingOnLoad();
                }
            }
        ]
    });
</script>
</body>
</html>
